library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;


entity mult is
generic (N : integer := 32);
port (	A 	: in  std_logic_vector (N/2-1 downto 0);
		B 	: in  std_logic_vector (N/2-1 downto 0);
		sign	: in  std_logic;
		M	: out std_logic_vector (N-1 downto 0)
);
end entity;

architecture Structural of mult is
    
type SignalVector is array (N/4-1 downto 0) of std_logic_vector (N-1 downto 0);
type SignalSel is array (N/4-1 downto 0) of std_logic_vector (2 downto 0);

component booth_mux is
generic (N : integer := 16);
port( M0  	: in  std_logic_vector (N-1 downto 0);
      M1  	: in  std_logic_vector (N-1 downto 0);
      M2  	: in  std_logic_vector (N-1 downto 0);
      M3  	: in  std_logic_vector (N-1 downto 0);
      M4  	: in  std_logic_vector (N-1 downto 0);
      SEL 	: in  std_logic_vector (2 downto 0);
      MOUT	: out std_logic_vector (N-1 downto 0)
);
end component;

component RCA is
generic(N : integer := 8);
port(	A_rca	: in   std_logic_vector (N-1 downto 0);
		B_rca	: in   std_logic_vector (N-1 downto 0);
		S_rca	: out std_logic_vector (N-1 downto 0);
		C_i		: in   std_logic;
		C_o		: out std_logic
);
end component;
  
component adder_evo is
generic (	N : integer := 16;
		M : integer := 4);
port(	A	: in   std_logic_vector (N-1 downto 0);
		B	: in   std_logic_vector (N-1 downto 0);
		C_in	: in   std_logic;
		SUB	: in   std_logic;
		SIGN: in   std_logic;
		OVF	: out std_logic;
		S 	: out std_logic_vector (N-1 downto 0)
);
end component;

	signal muxout	: SignalVector;
	signal sumout	: SignalVector;
	signal zeros 	: std_logic_vector (N-1 downto 0);
	signal nA		: std_logic_vector (N/2-1 downto 0);
	
	signal M1_i	: SignalVector;
	signal M2_i	: SignalVector;
	signal M3_i	: SignalVector;
	signal M4_i	: SignalVector;
	signal SEL_i	: SignalSel;

      signal nA_tmp : std_logic_vector (N/2-1 downto 0);
begin      
   
	zeros <= (others=>'0');
	nA_tmp <= not A;
	
	oneadder: RCA generic map (N/2) port	--nA <= not(A) + 1;
		map (	 A_rca	=> nA_tmp,
				B_rca	=> zeros(N/2-1 downto 0),
				S_rca	=> nA,
				C_i		=> '1',
				C_o		=> open
			);

	--first line of muxers (adders are present in the generate statement)
		M1_i(0)(N-1 downto N/2)		<= (others => '0');
		M1_i(0)(N/2-1 downto 0)		<= A;
		M2_i(0)(N-1 downto N/2)		<= (others => nA(N/2-1)); --sign extension
		M2_i(0)(N/2-1 downto 0)		<= nA;
		M3_i(0)(N-1 downto N/2+1)	<= (others => '0');
		M3_i(0)(N/2 downto 1)		<= A;
		M3_i(0)(0)					<= '0';
		M4_i(0)(N-1 downto N/2+1)	<= (others => nA(N/2-1));
		M4_i(0)(N/2 downto 1)		<= nA;
		M4_i(0)(0)					<= '0';

		SEL_i(0)						<= (B(1),B(0),'0');		--booth "prediction"

		enc0: booth_mux generic map(N) port
			map (	M0		=> zeros,
					M1		=> M1_i(0),
					M2		=> M2_i(0),
					M3		=> M3_i(0),
					M4		=> M4_i(0),
					SEL		=> SEL_i(0),
					MOUT 	=> sumout(0)
				); 

	--now we generate the muxes and adders (as many as we need) and connect their inputs to each other outputs
	righe: for riga in 1 to N/4-1 generate
		M1_i(riga)(N-1 downto N/2+2*riga)		<= (others => '0');
		M1_i(riga)(N/2+2*riga-1 downto 2*riga)	<= A;
		M1_i(riga)(2*riga-1 downto 0)			<= (others => '0');
		M2_i(riga)(N-1 downto N/2+2*riga)		<= (others => nA(N/2-1));
		M2_i(riga)(N/2+2*riga-1 downto 2*riga)	<= nA;
		M2_i(riga)(2*riga-1 downto 0)			<= (others => '0');
		M3_i(riga)(N-1 downto N/2+(2*riga)+1)	<= (others => '0');
		M3_i(riga)(N/2+2*riga downto 2*riga+1)	<= A;
		M3_i(riga)(2*riga downto 0)			<= (others => '0');
		M4_i(riga)(N-1 downto N/2+(2*riga)+1)	<= (others => nA(N/2-1));
		M4_i(riga)(N/2+2*riga downto 2*riga+1) <= nA;
		M4_i(riga)(2*riga downto 0)			<= (others => '0');
		
		SEL_i(riga) <= B(riga*2+1) & B(riga*2) & B(riga*2-1);

		enc: booth_mux generic map (N) port 
			map (	M0		=> zeros,
					M1		=> M1_i(riga),
					M2		=> M2_i(riga),
					M3		=> M3_i(riga),
					M4		=> M4_i(riga),
					SEL		=> SEL_i(riga),
					MOUT	=> muxout(riga-1)
				);

		sum: adder_evo generic map (N,5) port
			map (	A		=> muxout(riga-1),
					B		=> sumout(riga-1),
					C_in		=> '0',
					SUB		=> '0',
					SIGN	=> sign,
					OVF		=> open,
					S		=> sumout(riga)
				); 
	end generate righe;

	M <= sumout(N/4-1);		--actual result store in the last element
			 
end Structural;

--architecture Behavioral of mult is
--signal tmp : signed (N-1 downto 0);
--begin
--
--multiplier: process (A,B,sign) is
--begin
--
--	if sign = '0'
--	then
--		tmp <= (others => '0'); 
--		M <= STD_LOGIC_VECTOR (unsigned(A) * unsigned(B));
--	else
--		tmp <= signed(A) * signed(B);
--		M <= STD_LOGIC_VECTOR (tmp);
--	end if;
--
--end process;
--
--end;
